package com.gxa.saas.portal.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gxa.saas.core.entity.dto.luoj.*;
import com.gxa.saas.core.entity.vo.luoj.OrderCartVO;
import com.gxa.saas.core.entity.vo.luoj.SecKillInfoVO;
import com.gxa.saas.core.entity.vo.luoj.SecKillVO;
import com.gxa.saas.core.exception.BusinessException;
import com.gxa.saas.core.exception.ExceptionCode;
import com.gxa.saas.portal.mapper.AddressMapper;
import com.gxa.saas.portal.mapper.OrderCartMapper;
import com.gxa.saas.portal.mapper.SecKillDTOMapper;
import com.gxa.saas.portal.mapper.SecKillMapper;
import com.gxa.saas.portal.service.SeckillService;
import com.gxa.saas.portal.util.Uuid;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Validated
public class SeckillServiceImpl extends ServiceImpl<SecKillMapper, SecKillVO> implements SeckillService {

    @Resource(name = "MyJmsTemplate")
    private JmsMessagingTemplate jmsMessagingTemplate;

    public static final String SEC_KILL_ORDER = "seckillOrder";

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private SecKillDTOMapper secKillDTOMapper;

    private static final String SEK_KILL = "seckill:";

    private static final String LOCK = "LOCK:";

    @Override
    public Boolean setSeckill(@Validated SecKillDTO secKillDTO) {
        List<SecKillDTO> secKillDTOS = secKillDTOMapper.selectList(new QueryWrapper<SecKillDTO>().eq("time", secKillDTO.getTime()));
        if (secKillDTOS.size() > 0) {
            for (SecKillDTO killDTO : secKillDTOS) {
                redisTemplate.opsForValue().set((SEK_KILL + killDTO.getProductId()), killDTO.getStockCount());
            }
            return true;
        }
        else{
            return false;
        }
    }

    @Override
    public Boolean seckill(Integer id, Integer pid) throws BusinessException, JsonProcessingException {
        ValueOperations stringOps = redisTemplate.opsForValue();
        String value = UUID.randomUUID().toString().replaceAll("-", "");
        Boolean localSuccess = stringOps.setIfAbsent(LOCK + id, value, 5, TimeUnit.SECONDS);
        if (!localSuccess) {
            return false;
        }
        Object num = stringOps.get(SEK_KILL + pid);
        if (StringUtils.isEmpty(num)) {
            throw new BusinessException(ExceptionCode.NULL_GOODS_ID);
        }
        if (Integer.parseInt(num.toString()) <= 0) {
            return false;
        }
        stringOps.decrement(SEK_KILL + pid);
        System.out.println("秒杀成功，商品库存剩余：" + (Integer.parseInt(num.toString()) - 1));
        this.save(new SecKillVO(id, pid));//写入数据库
        SecKillInfoVO secKillVO = new SecKillInfoVO();
        secKillVO.setUserId(id);
        secKillVO.setGoodsId(pid);
        ObjectMapper objectMapper = new ObjectMapper();
        String info = objectMapper.writeValueAsString(secKillVO);
        jmsMessagingTemplate.convertAndSend(SEC_KILL_ORDER,info);
        if (stringOps.get(LOCK + id).equals(value)) {
            redisTemplate.delete(LOCK + id);
        }
        return true;
    }

    @Override
    public List<SecKillDTO> getSecKill() {
        SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd");
        String time = timeFormat.format(new Date());
        SimpleDateFormat endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = endTime.format(new Date());
        List<SecKillDTO> secKillDTOS = secKillDTOMapper.selectList(new QueryWrapper<SecKillDTO>().eq("time", time).lt("end_time", format));
        for (SecKillDTO secKillDTO : secKillDTOS) {
            redisTemplate.opsForValue().set(SEK_KILL + secKillDTO.getProductId(), secKillDTO.getStockCount());
        }
        return secKillDTOS;
    }
}
